import cv2
import threading
import logging
import time
import os

# 设置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class Camera:
    def __init__(self):
        self.video_capture = None
        self.is_running = False
        self.frame = None
        self.thread = None
        self.lock = threading.Lock()
        self.camera_backend = "opencv"  # 默认使用opencv

    def detect_camera_backend(self):
        """检测合适的摄像头后端"""
        logger.info("检测摄像头后端...")
        
        # 检查是否是树莓派环境
        is_rpi = False
        if os.path.exists('/proc/device-tree/model'):
            with open('/proc/device-tree/model', 'r') as f:
                model = f.read()
                if 'Raspberry Pi' in model:
                    logger.info("检测到树莓派环境")
                    is_rpi = True
        
        # 在树莓派上优先尝试libcamera backend
        if is_rpi:
            # 检查OpenCV是否支持libcamera
            backends = [cv2.CAP_LIBCAMERA, cv2.CAP_V4L2, cv2.CAP_ANY]
            backend_names = ["libcamera", "v4l2", "any"]
            
            for backend, name in zip(backends, backend_names):
                try:
                    logger.info(f"尝试使用 {name} 后端...")
                    cap = cv2.VideoCapture(0, backend)
                    if cap.isOpened():
                        width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
                        height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
                        logger.info(f"{name} 后端可用，分辨率: {width}x{height}")
                        cap.release()
                        self.camera_backend = name
                        return backend
                    cap.release()
                except Exception as e:
                    logger.warning(f"{name} 后端不可用: {e}")
        
        # 默认使用标准OpenCV
        self.camera_backend = "opencv"
        logger.info("使用标准OpenCV后端")
        return cv2.CAP_ANY

    def start(self):
        if not self.is_running:
            logger.info("正在初始化摄像头...")
            
            # 检测合适的后端
            backend = self.detect_camera_backend()
            
            try:
                # 尝试打开摄像头
                self.video_capture = cv2.VideoCapture(0, backend)
                
                # 如果失败，尝试不指定后端
                if not self.video_capture.isOpened():
                    logger.warning("使用指定后端无法打开摄像头，尝试默认方式...")
                    self.video_capture.release()
                    self.video_capture = cv2.VideoCapture(0)
                
                # 如果还是失败，尝试其他设备索引
                if not self.video_capture.isOpened():
                    logger.error("无法打开摄像头设备0")
                    for i in range(1, 5):
                        self.video_capture = cv2.VideoCapture(i, backend)
                        if self.video_capture.isOpened():
                            logger.info(f"使用摄像头设备 {i}")
                            break
                
                # 最终检查
                if not self.video_capture.isOpened():
                    logger.error("无法打开任何摄像头设备")
                    # 创建一个错误图像
                    import numpy as np
                    self.frame = np.zeros((480, 640, 3), dtype=np.uint8)
                    cv2.putText(self.frame, 'Camera Init Failed', (50, 240), 
                               cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
                    cv2.putText(self.frame, f'Backend: {self.camera_backend}', (50, 280), 
                               cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 1)
                    return False
                
                # 设置摄像头参数
                self.video_capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
                self.video_capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
                self.video_capture.set(cv2.CAP_PROP_FPS, 30)
                
                # 获取实际的摄像头参数
                width = self.video_capture.get(cv2.CAP_PROP_FRAME_WIDTH)
                height = self.video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT)
                fps = self.video_capture.get(cv2.CAP_PROP_FPS)
                logger.info(f"摄像头参数 - 分辨率: {width}x{height}, FPS: {fps}, 后端: {self.camera_backend}")
                
            except Exception as e:
                logger.error(f"初始化摄像头时出错: {e}")
                # 创建错误图像
                import numpy as np
                self.frame = np.zeros((480, 640, 3), dtype=np.uint8)
                cv2.putText(self.frame, 'Camera Error', (50, 240), 
                           cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
                cv2.putText(self.frame, str(e)[:50], (50, 280), 
                           cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 1)
                return False
            
            self.is_running = True
            self.thread = threading.Thread(target=self.update)
            self.thread.daemon = True  # 设置为守护线程
            self.thread.start()
            logger.info("摄像头初始化完成")
            return True
        return True

    def update(self):
        logger.info(f"摄像头捕获线程已启动 (后端: {self.camera_backend})")
        while self.is_running:
            if self.video_capture is not None and self.video_capture.isOpened():
                try:
                    ret, frame = self.video_capture.read()
                    if ret:
                        with self.lock:
                            self.frame = frame.copy()
                    else:
                        logger.warning("无法从摄像头读取帧")
                except Exception as e:
                    logger.error(f"读取摄像头帧时出错: {e}")
            else:
                # 使用错误图像
                import numpy as np
                error_frame = np.zeros((480, 640, 3), dtype=np.uint8)
                cv2.putText(error_frame, 'Camera Disconnected', (50, 240), 
                           cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
                with self.lock:
                    self.frame = error_frame.copy()
            
            # 短暂休眠以避免过度占用CPU
            time.sleep(1/30)  # 约30FPS
            
        logger.info("摄像头捕获线程已停止")

    def read(self):
        with self.lock:
            return self.frame is not None, self.frame.copy() if self.frame is not None else None

    def stop(self):
        logger.info("正在停止摄像头...")
        self.is_running = False
        if self.thread is not None:
            self.thread.join(timeout=1)  # 设置超时时间
        if self.video_capture is not None:
            self.video_capture.release()
            self.video_capture = None
        logger.info("摄像头已停止")

    def gen_frames(self):
        logger.info("开始生成视频帧...")
        # 确保摄像头已启动
        if not self.is_running:
            self.start()
            
        frame_count = 0
        start_time = time.time()
        
        while self.is_running:
            success, frame = self.read()
            if not success:
                # 如果无法读取帧，创建一个错误提示图像
                import numpy as np
                frame = np.zeros((480, 640, 3), dtype=np.uint8)
                cv2.putText(frame, 'No Camera Feed', (50, 240), 
                           cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
                cv2.putText(frame, 'Check camera connection', (50, 280), 
                           cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 1)
            
            # 编码帧
            try:
                ret, buffer = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 70])
                if ret:
                    frame_count += 1
                    # 每30帧记录一次FPS
                    if frame_count % 30 == 0:
                        elapsed = time.time() - start_time
                        fps = 30 / elapsed if elapsed > 0 else 0
                        logger.debug(f"视频流 FPS: {fps:.2f}")
                        start_time = time.time()
                    
                    yield (b'--frame\r\n'
                           b'Content-Type: image/jpeg\r\n\r\n' + buffer.tobytes() + b'\r\n')
                else:
                    logger.warning("无法编码视频帧")
            except Exception as e:
                logger.error(f"编码视频帧时出错: {e}")
                
            # 控制帧率，避免过度占用CPU
            time.sleep(1/30)  # 限制在30FPS
            
        logger.info("视频帧生成已停止")